package com.mgq.java8.collector;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;

/**
 * <b>功能：</b>自定义质数收集器<br>
 * <b>Copyright mgq</b>
 * <li>版本&nbsp;&nbsp;&nbsp;&nbsp;修改日期&nbsp;&nbsp;&nbsp;&nbsp;部　　门&nbsp;&nbsp;&nbsp;&nbsp;作　者&nbsp;&nbsp;&nbsp;&nbsp;变更内容</li><hr>
 * <li>v1.0&nbsp;&nbsp;&nbsp;&nbsp;20220404&nbsp;&nbsp;营业后台&nbsp;&nbsp;&nbsp;&nbsp;马广奇&nbsp;&nbsp;&nbsp;&nbsp;创建类</li>
 * <br><br>
 * Collector<T, A, R>
 * T:元素类型
 * A:accumulator 累加器类型
 * R:return 返回值类型
 *
 * @author 马广奇
 * @version 2022-04-04 11:49
 */
public class PrimeNumbersCollector implements Collector<Integer, Map<Boolean, List<Integer>>, Map<Boolean, List<Integer>>> {
    @Override
    public Supplier<Map<Boolean, List<Integer>>> supplier() {
        return () -> new HashMap<>() {
            //双括号初始化
            {
                put(true, new ArrayList<>());
                put(false, new ArrayList<>());
            }
        };
    }

    @Override
    public BiConsumer<Map<Boolean, List<Integer>>, Integer> accumulator() {
        //acc.get(true)获取是质数的集合. isPrime()判断是否是质数. acc.get()将结果加入到对应的集合(true或者false list中)
        return (Map<Boolean, List<Integer>> acc, Integer candidate) -> acc.get(isPrime(acc.get(true),candidate)).add(candidate);
    }

    /**
     * 判断是否是质数.
     * 首先取出list中小于平方根的的集合
     * 然后判断是否是质数
     *
     * 优化: 仅仅使用质数来作为除数,判断一个数能否被质数整除即可
     * @param primes 质数集合
     * @param candidate 候选数
     */
    public boolean isPrime(List<Integer> primes, int candidate) {
        int candidateRoot = (int) Math.sqrt(candidate);

        return takeWhile(primes, i -> i <= candidateRoot)
                .stream().noneMatch(p -> candidate % p == 0);
    }

    /**
     * 取出list中满足predicate条件的元素
     */
    public static <A> List<A> takeWhile(List<A> list, Predicate<A> p) {
        int i = 0;
        for (A item : list) {
            //检查列表中的当前item是否满足predicate
            if (!p.test(item)) {
                //不满足,返回该list的前缀列表
                return list.subList(0, i);
            }
            i++;
        }
        return list;
    }

    @Override
    public BinaryOperator<Map<Boolean, List<Integer>>> combiner() {
        //并行工作
        return (map1, map2) -> {
            map1.get(true).addAll(map2.get(true));
            map1.get(false).addAll(map2.get(false));
            return map1;
        };
    }

    @Override
    public Function<Map<Boolean, List<Integer>>, Map<Boolean, List<Integer>>> finisher() {
        //原样返回,不用转换结果
        return Function.identity();
    }

    @Override
    public Set<Characteristics> characteristics() {
        return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH));
    }
}
